﻿using AwesomeChromeFormUI.Attributes;
using AwesomeChromeFormUI.Constants;
using AwesomeChromeFormUI.Handlers;
using AwesomeChromeFormUI.Utils;
using CefSharp;
using CefSharp.JavascriptBinding;
using CefSharp.WinForms;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;


namespace AwesomeChromeFormUI.CommonExtensions
{
    public static class BrowserExtensions
    {
        /// <summary>
        /// 标志位，是否已经设置了命名转换器
        /// </summary>
        private static bool IsSetNameConverter = false;

        /// <summary>
        /// 程序集缓存
        /// </summary>
        private static IDictionary<string,Type> TypesDic;

        /// <summary>
        /// 遍历程序集，找到带 JavascriptObjectAttribute 注解的类
        /// </summary>
        /// <returns></returns>
        private static void FindJavascriptObjectAttribute()
        {
            TypesDic = AppDomain.CurrentDomain.GetAssemblies()
               .SelectMany(a => a.GetTypes())
               .Where(t => t.IsClass && t.GetCustomAttribute<JavascriptObjectAttribute>() != null)
               .ToDictionary(t => t.Name.ToUpper(), t => t);
        }

        /// <summary>
        ///  注册 Notnet 方法 [Core]
        /// </summary>
        /// <param name="repo"></param>
        /// <param name="eventObjectName"></param>
        private static void DoRegisterDotNetMethod(IJavascriptObjectRepository repo, string eventObjectName)
        {
            if (TypesDic == null || !TypesDic.ContainsKey(eventObjectName.ToUpper()))
            {
                return;
            }

            Type type = TypesDic[eventObjectName.ToUpper()];
            Debug.WriteLine("找到带注解的class: " + type.Name);
            // 获取类的构造函数
            ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
            if (constructor == null)
            {
                Debug.WriteLine("没有找到无参构造函数");
                return;
            }

            if (constructor != null)
            {
                BindingOptions bindingOptions = BindingOptions.DefaultBinder;
                // 使用构造函数创建对象
                object objectToBind = constructor.Invoke(null);
                // 打印对象
                Debug.WriteLine("创建对象: " + objectToBind.ToString());
                repo.Register(eventObjectName, objectToBind, isAsync: true, options: bindingOptions);

            }

        }

        /// <summary>
        /// 处理 DotNet 实例并绑定到 Javascript 
        /// </summary>
        /// <param name="browser"></param>
        public static void ResolveDotNetObjectThenBoundInJavascript(this ChromiumWebBrowser browser)
        {
            FindJavascriptObjectAttribute();

            // 注册 js 对象
            browser.JavascriptObjectRepository.ResolveObject += (sender, e) =>
            {
                if (!IsSetNameConverter)
                {
                    e.ObjectRepository.NameConverter = new CamelCaseJavascriptNameConverter();
                    IsSetNameConverter = true;
                }

                DoRegisterDotNetMethod(e.ObjectRepository, e.ObjectName);
            };

            browser.JavascriptObjectRepository.ObjectBoundInJavascript += (sender, e) =>
            {
                //string name = e.ObjectName;
                Debug.WriteLine($"Object {e.ObjectName} was bound successfully.");
            };

        }

        /// <summary>
        /// 设置自定义菜单
        /// </summary>
        /// <param name="browser"></param>
        public static void SetExtensionMenu(this ChromiumWebBrowser browser)
        {
            browser.MenuHandler = new DefaultContextMenuHandler();
        }

        /// <summary>
        /// 处理鼠标信息
        /// </summary>
        /// <param name="browser"></param>
        public static void SetMouseDownJavascriptMessageReceived(this ChromiumWebBrowser browser)
        {
            browser.JavascriptMessageReceived += MouseDownJavascriptMessageReceived;
        }

        /// <summary>
        /// 接收前端 js 传的 msg
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MouseDownJavascriptMessageReceived(object sender, JavascriptMessageReceivedEventArgs e)
        {
            if (e.Message != null)
            {
                dynamic msg = e.Message;
                switch (msg.type)
                {
                    case SystemConstant.MOUSERDOWN:
                        {
                            MainViewUtil.GetCurrentForm().DragWindow();
                            break;
                        }
                    case SystemConstant.MINIMIZED:
                        {
                            MainViewUtil.GetCurrentForm().ChangeWindowState(SystemConstant.MINIMIZED);
                            break;
                        }
                    case SystemConstant.CLOSE:
                        {
                            MainViewUtil.GetCurrentForm().ChangeWindowState(SystemConstant.CLOSE);
                            break;
                        }
                    case SystemConstant.NORMALIZED:
                        {
                            MainViewUtil.GetCurrentForm().ChangeWindowState(SystemConstant.NORMALIZED);
                            break;
                        }
                    case SystemConstant.RELOAD:
                        {
                            e.Browser.Reload();
                            break;
                        } 
                    default: break;
                }
            };
        }


        /// <summary>
        /// 设置默认标题框
        /// </summary>
        /// <param name="browser"></param>
        public static void SetDefaultTitleBar(this ChromiumWebBrowser browser)
        {
            // browser 开始加载事件
            browser.FrameLoadStart += (s, e) =>
            {
                Debug.WriteLine("FrameLoadStart => " + e.Frame.Name);
                // 加载网页时注入 js 请求静态资源
                //e.Frame.ExecuteJavaScriptAsync(@"(function () {
                //        var link = document.createElement('link');
                //        link.rel = 'stylesheet';
                //        link.href = 'http://localhost:5173/public/index.css';
                //        document.head.appendChild(link);
                //     })();");

            };

            // browser 加载状态变更事件
            browser.LoadingStateChanged += (s, e) =>
            {
                Debug.WriteLine("IsLoading => " + e.IsLoading);
            };

            // browser 加载完成事件
            browser.FrameLoadEnd += DefaultFrameLoadEnd;
        }

        /// <summary>
        /// Browser 加载完成事件
        /// 这里进行自定义 js 注入，例如鼠标事件监听、样式特效、新增标题
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void DefaultFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            // Wait for the MainFrame to finish loading
            if (e.Frame.IsMain)
            {
                // 注入 jq 与生成标题框
                e.Frame.ExecuteJavaScriptAsync(GetJsInjectionString());
            }
        }

        /// <summary>
        /// 获取 js 注入脚本
        /// </summary>
        /// <returns></returns>
        private static string GetJsInjectionString()
        {
            // 标题栏
            string filePath = Path.Combine(Directory.GetCurrentDirectory(), "JsInjection","my-js-injection.js");

            // 可拖拽区域
            //string filePath = Path.Combine(Directory.GetCurrentDirectory(), "JsInjection", "set-draggable-region.js");

            // 控制浏览器滚动条居中
            //string filePath = Path.Combine(Directory.GetCurrentDirectory(), "JsInjection", "window-scroll-to-screen-center.js");

            return File.ReadAllText(filePath);
        }
    }
}
